package com.campus.secondhand.service.impl;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.campus.secondhand.common.Result;
import com.campus.secondhand.entity.Product;
import com.campus.secondhand.entity.User;
import com.campus.secondhand.entity.ProductImages;
import com.campus.secondhand.mapper.ProductImageMapper;
import com.campus.secondhand.mapper.ProductMapper;
import com.campus.secondhand.model.dto.ProductCreateDTO;
import com.campus.secondhand.model.dto.ProductUpdateDTO;
import com.campus.secondhand.model.vo.ProductDetailVO;
import com.campus.secondhand.model.vo.ProductListVO;
import com.campus.secondhand.model.vo.ProductImageVO;
import com.campus.secondhand.service.CategoryService;
import com.campus.secondhand.service.FavoriteService;
import com.campus.secondhand.service.ProductService;
import com.campus.secondhand.service.SchoolService;
import com.campus.secondhand.service.UserService;
import com.campus.secondhand.service.MessageService;
import com.campus.secondhand.model.dto.MessageSendDTO;
import com.campus.secondhand.model.vo.ConversationVO;
import com.campus.secondhand.model.vo.MessageVO;

import lombok.extern.slf4j.Slf4j;

/**
 * 商品服务实现类
 */
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    private final UserService userService;
    private final CategoryService categoryService;
    private final SchoolService schoolService;
    private final FavoriteService favoriteService;
    private final ProductImageMapper productImageMapper;
    private final MessageService messageService;
    private final RedisTemplate<String, Object> redisTemplate;

    // Redis缓存键常量
    private static final String CACHE_PRODUCT_PREFIX = "product:";
    private static final String CACHE_PRODUCT_DETAIL = "product:detail:";
    private static final String CACHE_PRODUCT_LIST = "product:list:";
    private static final String CACHE_PRODUCT_POPULAR = "product:popular";
    private static final String CACHE_PRODUCT_NEARBY = "product:nearby:";
    private static final String CACHE_PRODUCT_RECOMMENDED = "product:recommended:";
    private static final String CACHE_PRODUCT_IMAGES = "product:images:";
    private static final long CACHE_EXPIRATION = 12; // 缓存过期时间，单位小时

    public ProductServiceImpl(
            UserService userService,
            CategoryService categoryService,
            SchoolService schoolService,
            @Lazy FavoriteService favoriteService,
            ProductImageMapper productImageMapper,
            @Lazy MessageService messageService,
            RedisTemplate<String, Object> redisTemplate) {
        this.userService = userService;
        this.categoryService = categoryService;
        this.schoolService = schoolService;
        this.favoriteService = favoriteService;
        this.productImageMapper = productImageMapper;
        this.messageService = messageService;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 获取商品列表
     */
    @Override
    public Result<Page<ProductListVO>> getProductList(Long categoryId, Long schoolId, String keyword,
            Double minPrice, Double maxPrice, String sortField,
            String sortOrder, Double longitude, Double latitude,
            Pageable pageable, Long currentUserId) {
        // 构建缓存Key，包含所有查询参数
        // 构建缓存Key，不包含查询参数，便于后续删除操作
        StringBuilder cacheKeyBuilder = new StringBuilder(CACHE_PRODUCT_LIST);

        // 用户特定的结果（如是否收藏）应该有独立的缓存
        String cacheKey = cacheKeyBuilder.toString();
        if (currentUserId != null) {
            cacheKey += "user:" + currentUserId;
        }

        // 对于基于位置的查询，不使用缓存，因为位置可能频繁变化
        if (longitude == null || latitude == null) {
            // 尝试从缓存获取
            Object cachedResult = redisTemplate.opsForValue().get(cacheKey);
            if (cachedResult != null) {
                try {
                    // 将缓存的Map数据转换回Page对象
                    java.util.Map<String, Object> pageData = (java.util.Map<String, Object>) cachedResult;
                    java.util.List<ProductListVO> content = (java.util.List<ProductListVO>) pageData.get("content");
                    long totalElements = ((Number) pageData.get("totalElements")).longValue();
                    int number = ((Number) pageData.get("number")).intValue();
                    int size = ((Number) pageData.get("size")).intValue();

                    Page<ProductListVO> pageResult = new PageImpl<>(
                            content, org.springframework.data.domain.PageRequest.of(number, size), totalElements);

                    return Result.success(pageResult, "获取成功(缓存)");
                } catch (Exception e) {
                    log.warn("缓存数据反序列化失败", e);
                    // 缓存数据有问题，继续查询数据库
                }
            }
        }

        // 构建查询条件
        LambdaQueryWrapper<Product> queryWrapper = Wrappers.lambdaQuery(Product.class);

        // 只查询在售商品
        queryWrapper.eq(Product::getStatus, 1);

        // 添加各种查询条件
        if (categoryId != null) {
            queryWrapper.eq(Product::getCategoryId, categoryId);
        }

        if (schoolId != null) {
            queryWrapper.eq(Product::getSchoolId, schoolId);
        }

        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                    .like(Product::getName, keyword)
                    .or()
                    .like(Product::getDescription, keyword));
        }

        if (minPrice != null) {
            queryWrapper.ge(Product::getPrice, minPrice);
        }

        if (maxPrice != null) {
            queryWrapper.le(Product::getPrice, maxPrice);
        }

        // 设置排序
        if ("price".equals(sortField)) {
            if ("desc".equals(sortOrder)) {
                queryWrapper.orderByDesc(Product::getPrice);
            } else {
                queryWrapper.orderByAsc(Product::getPrice);
            }
        } else if ("views".equals(sortField)) {
            queryWrapper.orderByDesc(Product::getViews);
        } else {
            // 默认按创建时间排序
            queryWrapper.orderByDesc(Product::getCreatedAt);
        }

        // 设置分页 - 修正分页参数处理
        // 使用MyBatis-Plus分页时，将页码从0开始改为从1开始计数
        int pageNumber = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();

        // 打印分页参数用于调试
        log.info("请求分页参数 - 页码: {}, 每页大小: {}", pageNumber, pageSize);

        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> mybatisPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                pageNumber + 1, // 从0开始的页码转为从1开始
                pageSize);

        // 执行查询
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> productPage = page(mybatisPage,
                queryWrapper);

        // 打印查询结果信息用于调试
        log.info("查询结果 - 总记录数: {}, 总页数: {}, 当前页码: {}, 当前页记录数: {}",
                productPage.getTotal(), productPage.getPages(),
                productPage.getCurrent(), productPage.getRecords().size());

        // 转换为VO
        List<ProductListVO> voList = productPage.getRecords().stream()
                .map(product -> convertToListVO(product, currentUserId)) // 传递 currentUserId
                .collect(Collectors.toList());

        // 计算距离（如果提供了经纬度）
        if (longitude != null && latitude != null) {
            calculateDistance(voList, longitude, latitude);
        }

        // 创建Spring Data的Page对象
        Page<ProductListVO> resultPage = new PageImpl<>(
                voList, pageable, productPage.getTotal());

        // 写入缓存（只缓存非位置相关的查询）
        if (longitude == null && latitude == null) {
            // 创建包含分页信息的Map而不是直接缓存PageImpl对象
            java.util.Map<String, Object> pageData = new java.util.HashMap<>();
            pageData.put("content", new ArrayList<>(voList)); // 确保使用可序列化的ArrayList
            pageData.put("totalElements", productPage.getTotal());
            pageData.put("number", pageable.getPageNumber());
            pageData.put("size", pageable.getPageSize());

            redisTemplate.opsForValue().set(cacheKey, pageData, CACHE_EXPIRATION / 2, TimeUnit.HOURS); // 商品列表缓存时间较短
        }

        return Result.success(resultPage, "获取成功");
    }

    /**
     * 获取商品详情
     */
    @Override
    public Result<ProductDetailVO> getProductDetail(Long id, Long userId) {
        // 尝试从缓存获取
        String cacheKey = CACHE_PRODUCT_DETAIL + id;
        if (userId != null) {
            cacheKey += ":" + userId;
        }

        Object cachedDetail = redisTemplate.opsForValue().get(cacheKey);
        if (cachedDetail != null) {
            try {
                return Result.success((ProductDetailVO) cachedDetail, "获取成功(缓存)");
            } catch (Exception e) {
                log.warn("商品详情缓存反序列化失败", e);
                // 继续查询数据库
            }
        }

        // 缓存未命中，从数据库获取
        Product product = getById(id);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 转换为VO
        ProductDetailVO detailVO = convertToDetailVO(product);

        // 判断当前用户是否已收藏
        if (userId != null) {
            detailVO.setIsFavorite(favoriteService.isFavorite(userId, id));
        }

        // 写入缓存
        redisTemplate.opsForValue().set(cacheKey, detailVO, CACHE_EXPIRATION, TimeUnit.HOURS);

        return Result.success(detailVO, "获取成功");
    }

    /**
     * 发布商品
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Long> createProduct(Long userId, ProductCreateDTO createDTO) {
        // 获取用户信息
        User user = userService.getUserById(userId);
        if (user == null) {
            return Result.error(404, "用户不存在");
        }

        // 创建商品对象
        Product product = new Product();
        BeanUtils.copyProperties(createDTO, product);

        // 设置其他属性
        product.setSellerId(userId);
        product.setSchoolId(user.getSchoolId());
        product.setViews(0);
        product.setStatus(1); // 1表示在售
        product.setDeleted(0); // 显式设置deleted=0，防止数据库完整性错误
        product.setCreatedAt(LocalDateTime.now());
        product.setUpdatedAt(LocalDateTime.now());

        // 保存商品
        boolean success = save(product);
        if (!success) {
            return Result.error("商品发布失败");
        }

        // 保存商品图片信息
        Long productId = product.getId();
        List<String> imageUrls = createDTO.getImageUrls();
        if (imageUrls != null && !imageUrls.isEmpty()) {
            for (int i = 0; i < imageUrls.size(); i++) {
                ProductImages productImage = new ProductImages();
                productImage.setProductId(productId);

                // 从完整路径中提取文件名
                String imageUrl = imageUrls.get(i);
                String filename = imageUrl;
                if (imageUrl.contains("/")) {
                    filename = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
                }

                productImage.setImageUrl(filename); // 只保存文件名
                productImage.setIsMain(i == 0 ? 1 : 0); // 第一张图片设为主图
                productImage.setSortOrder(i);
                productImage.setCreatedAt(LocalDateTime.now());
                productImage.setUpdatedAt(LocalDateTime.now());
                productImageMapper.insert(productImage);
            }
        }

        // 清除相关缓存（商品列表、热门、推荐等缓存）
        // 新增商品会影响商品列表、热门商品、推荐商品等缓存
        redisTemplate.delete(CACHE_PRODUCT_LIST + "*"); // 清除所有商品列表缓存
        redisTemplate.delete(CACHE_PRODUCT_POPULAR + "*"); // 清除热门商品缓存
        redisTemplate.delete(CACHE_PRODUCT_RECOMMENDED + "*"); // 清除推荐商品缓存
        // 近期商品缓存由于时间短，通常不需要主动清除，会自动过期

        return Result.success(product.getId(), "发布成功");
    }

    /**
     * 更新商品
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateProduct(Long id, Long userId, ProductUpdateDTO updateDTO) {
        Product product = getById(id);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 检查是否为卖家
        if (!product.getSellerId().equals(userId)) {
            return Result.error(403, "无权操作他人商品");
        }

        // 更新商品
        BeanUtils.copyProperties(updateDTO, product);
        product.setUpdatedAt(LocalDateTime.now());

        // 保存商品图片信息
        Long productId = product.getId();
        List<String> imageUrls = updateDTO.getImageUrls();
        if (imageUrls != null && !imageUrls.isEmpty()) {
            for (int i = 0; i < imageUrls.size(); i++) {
                ProductImages productImage = new ProductImages();
                productImage.setProductId(productId);

                // 从完整路径中提取文件名
                String imageUrl = imageUrls.get(i);
                String filename = imageUrl;
                if (imageUrl.contains("/")) {
                    filename = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
                }

                productImage.setImageUrl(filename); // 只保存文件名
                productImage.setIsMain(i == 0 ? 1 : 0); // 第一张图片设为主图
                productImage.setSortOrder(i);
                productImage.setCreatedAt(LocalDateTime.now());
                productImage.setUpdatedAt(LocalDateTime.now());
                productImageMapper.insert(productImage);
            }
        }

        boolean success = updateById(product);
        if (!success) {
            return Result.error("更新失败");
        }

        // 清除该商品的相关缓存
        clearProductCache(id);

        return Result.success(null, "更新成功");
    }

    /**
     * 删除商品
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> deleteProduct(Long id, Long userId) {
        Product product = getById(id);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 检查是否为卖家
        if (!product.getSellerId().equals(userId)) {
            return Result.error(403, "无权操作他人商品");
        }

        // 获取商品图片列表
        List<String> imageUrls = getProductImageUrls(product.getId());

        // 删除商品图片文件
        if (imageUrls != null && !imageUrls.isEmpty()) {
            for (String imageUrl : imageUrls) {
                try {
                    // 解析图片相对路径，转换为本地路径
                    if (imageUrl != null && imageUrl.startsWith("/images/")) {
                        String relativePath = imageUrl.substring("/images/".length());
                        Path imagePath = Paths.get("D:\\app\\cursor\\work\\campus-second-hand-Front\\public\\images",
                                relativePath);

                        // 删除文件
                        if (Files.exists(imagePath)) {
                            Files.delete(imagePath);
                            log.info("删除商品图片: {}", imagePath);
                        }
                    }
                } catch (IOException e) {
                    log.warn("删除商品图片失败: {}", e.getMessage());
                    // 继续处理，不中断删除流程
                }
            }
        }

        // 逻辑删除商品记录和关联的图片记录
        boolean success = removeById(id);
        if (!success) {
            return Result.error("删除失败");
        }

        // 删除商品图片记录
        LambdaQueryWrapper<ProductImages> queryWrapper = Wrappers.lambdaQuery(ProductImages.class)
                .eq(ProductImages::getProductId, id);
        productImageMapper.delete(queryWrapper);

        // 清除该商品的相关缓存
        clearProductCache(id);
        // 清除相关列表缓存
        redisTemplate.delete(CACHE_PRODUCT_LIST + "*");
        redisTemplate.delete(CACHE_PRODUCT_POPULAR + "*");
        redisTemplate.delete(CACHE_PRODUCT_RECOMMENDED + "*");

        return Result.success(null, "删除成功");
    }

    /**
     * 修改商品状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateProductStatus(Long id, Long userId, String status) {
        Product product = getById(id);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 检查是否为卖家
        if (!product.getSellerId().equals(userId)) {
            return Result.error(403, "无权操作他人商品");
        }

        // 更新状态
        int statusCode;
        switch (status) {
            case "on_sale":
                statusCode = 1;
                break;
            case "sold":
                statusCode = 2;
                break;
            case "off_shelf":
                statusCode = 3;
                break;
            default:
                return Result.error(400, "无效的状态值");
        }

        LambdaUpdateWrapper<Product> updateWrapper = Wrappers.lambdaUpdate(Product.class)
                .eq(Product::getId, id)
                .set(Product::getStatus, statusCode)
                .set(Product::getUpdatedAt, LocalDateTime.now());

        boolean success = update(updateWrapper);
        if (!success) {
            return Result.error("状态更新失败");
        }

        // 清除该商品的相关缓存
        clearProductCache(id);
        // 商品状态变化会影响商品列表、热门商品等
        redisTemplate.delete(CACHE_PRODUCT_LIST + "*");
        redisTemplate.delete(CACHE_PRODUCT_POPULAR + "*");
        redisTemplate.delete(CACHE_PRODUCT_RECOMMENDED + "*");

        return Result.success(null, "状态已更新");
    }

    /**
     * 获取用户发布的商品
     */
    @Override
    public Result<Page<ProductListVO>> getUserProducts(Long userId, Pageable pageable) {
        LambdaQueryWrapper<Product> queryWrapper = Wrappers.lambdaQuery(Product.class)
                .eq(Product::getSellerId, userId);

        // 按创建时间倒序
        queryWrapper.orderByDesc(Product::getCreatedAt);

        // 设置分页
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> mybatisPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                pageable.getPageNumber() + 1,
                pageable.getPageSize());

        // 执行查询
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> productPage = page(mybatisPage,
                queryWrapper);

        // 转换为VO
        List<ProductListVO> voList = productPage.getRecords().stream()
                .map(product -> convertToListVO(product, userId)) // 传入 userId
                .collect(Collectors.toList());

        // 创建Spring Data的Page对象
        Page<ProductListVO> resultPage = new PageImpl<>(
                voList, pageable, productPage.getTotal());

        return Result.success(resultPage, "获取成功");
    }

    /**
     * 上传商品图片
     */
    @Override
    public Result<String> uploadProductImage(Long userId, MultipartFile file) {
        if (file.isEmpty()) {
            return Result.error(400, "文件为空");
        }

        try {
            // 创建上传目录
            Path uploadPath = Paths.get("D:\\app\\cursor\\work\\campus-second-hand-Front\\public\\images\\product");
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }

            // 生成文件名
            String originalFilename = file.getOriginalFilename();
            String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String newFilename = UUID.randomUUID().toString() + extension;

            // 保存文件
            Path filePath = uploadPath.resolve(newFilename);
            Files.copy(file.getInputStream(), filePath);

            // 返回文件名 (不返回完整路径)
            // 客户端需要拼接前缀 "/images/product/" + newFilename
            return Result.success(newFilename, "上传成功");
        } catch (IOException e) {
            log.error("文件上传失败", e);
            return Result.error(500, "文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 增加商品浏览量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Integer> increaseProductViews(Long id) {
        // 获取商品信息
        Product product = getById(id);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 增加浏览量
        int newViews = product.getViews() + 1;

        LambdaUpdateWrapper<Product> updateWrapper = Wrappers.lambdaUpdate(Product.class)
                .eq(Product::getId, id)
                .set(Product::getViews, newViews);

        boolean success = update(updateWrapper);
        if (!success) {
            return Result.error("浏览量更新失败");
        }

        // 清除该商品的详情缓存
        String detailCacheKey = CACHE_PRODUCT_DETAIL + id;
        redisTemplate.delete(detailCacheKey);

        // 如果浏览量变化较大，可能会影响热门商品和推荐商品列表
        // 但如果每次浏览都清空这些缓存，会降低缓存效率
        // 这里采用一个折衷方案：当浏览量达到特定阈值（如100的倍数）时才清除相关缓存
        if (newViews % 100 == 0) {
            redisTemplate.delete(CACHE_PRODUCT_POPULAR + "*");
            redisTemplate.delete(CACHE_PRODUCT_RECOMMENDED + "*");
            log.info("商品ID：{} 浏览量达到 {} 次，清除热门和推荐商品缓存", id, newViews);
        }

        return Result.success(newViews, "浏览量已更新");
    }

    /**
     * 将Product实体转换为ProductListVO
     */
    private ProductListVO convertToListVO(Product product, Long currentUserId) {
        ProductListVO vo = new ProductListVO();
        BeanUtils.copyProperties(product, vo);

        // 设置分类名称
        vo.setCategoryName(categoryService.getCategoryName(product.getCategoryId()));

        // 设置卖家信息
        User seller = userService.getUserById(product.getSellerId());
        if (seller != null) {
            vo.setSellerName(seller.getNickname());
            vo.setSellerAvatar(seller.getAvatar());
        }

        // 设置收藏数量
        vo.setFavoriteCount(favoriteService.countProductFavorites(product.getId()));

        // 设置当前用户是否已收藏
        if (currentUserId != null) {
            vo.setIsFavorite(favoriteService.isFavorite(currentUserId, product.getId()));
        } else {
            vo.setIsFavorite(false); // 默认未收藏或未知
        }

        // 设置状态显示文本
        switch (product.getStatus()) {
            case 1:
                vo.setStatus("在售");
                break;
            case 2:
                vo.setStatus("已售");
                break;
            case 3:
                vo.setStatus("已下架");
                break;
            default:
                vo.setStatus("未知");
        }

        // 设置创建时间
        vo.setCreateTime(product.getCreatedAt());

        // 确保描述字段被设置
        vo.setDescription(product.getDescription());

        // 确保位置描述字段被设置
        vo.setLocationDescription(product.getLocationDescription());

        // 设置主图URL
        List<String> imageUrls = getProductImageUrls(product.getId());
        if (imageUrls != null && !imageUrls.isEmpty()) {
            vo.setMainImageUrl(imageUrls.get(0));
        }

        return vo;
    }

    /**
     * 将Product实体转换为ProductDetailVO
     */
    private ProductDetailVO convertToDetailVO(Product product) {
        ProductDetailVO vo = new ProductDetailVO();
        BeanUtils.copyProperties(product, vo);

        // 设置分类名称
        vo.setCategoryName(categoryService.getCategoryName(product.getCategoryId()));

        // 设置卖家信息
        User seller = userService.getUserById(product.getSellerId());
        if (seller != null) {
            vo.setSellerName(seller.getNickname());
            vo.setSellerAvatar(seller.getAvatar());
        }

        // 设置收藏数量
        vo.setFavoriteCount(favoriteService.countProductFavorites(product.getId()));

        // 设置图片URL列表
        vo.setImageUrls(getProductImageUrls(product.getId()));
        vo.setStatus(product.getStatus());
        return vo;
    }

    /**
     * 计算商品与用户的距离
     */
    private void calculateDistance(List<ProductListVO> products, double userLongitude, double userLatitude) {
        for (ProductListVO product : products) {
            if (product.getLongitude() != null && product.getLatitude() != null) {
                double distance = calculateDistanceInMeters(
                        userLatitude, userLongitude,
                        product.getLatitude().doubleValue(), product.getLongitude().doubleValue());
                product.setDistance(distance);
            }
        }
    }

    /**
     * 使用Haversine公式计算两点之间的距离（米）
     */
    private double calculateDistanceInMeters(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // 地球半径（千米）

        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);

        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                        * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return R * c * 1000; // 转换为米
    }

    /**
     * 获取商品的图片URL列表
     */
    private List<String> getProductImageUrls(Long productId) {
        // 使用MyBatis-Plus的LambdaQueryWrapper构建查询条件
        LambdaQueryWrapper<ProductImages> queryWrapper = Wrappers.lambdaQuery(ProductImages.class)
                .eq(ProductImages::getProductId, productId)
                .orderByDesc(ProductImages::getIsMain)
                .orderByAsc(ProductImages::getSortOrder)
                .select(ProductImages::getImageUrl);

        // 查询并转换为URL列表
        return productImageMapper.selectList(queryWrapper)
                .stream()
                .map(ProductImages::getImageUrl) // 直接返回数据库中的imageUrl字段
                .collect(Collectors.toList());
    }

    /**
     * 获取商品图片列表
     */
    @Override
    public Result<List<ProductImageVO>> getProductImages(Long productId) {
        // 尝试从缓存获取
        String cacheKey = CACHE_PRODUCT_IMAGES + productId;
        Object cachedImages = redisTemplate.opsForValue().get(cacheKey);
        if (cachedImages != null) {
            try {
                List<ProductImageVO> imageList = (List<ProductImageVO>) cachedImages;
                return Result.success(new ArrayList<>(imageList), "获取成功(缓存)");
            } catch (Exception e) {
                log.warn("商品图片缓存反序列化失败", e);
                // 继续查询数据库
            }
        }

        // 检查商品是否存在
        Product product = getById(productId);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 查询商品图片列表
        LambdaQueryWrapper<ProductImages> queryWrapper = Wrappers.lambdaQuery(ProductImages.class)
                .eq(ProductImages::getProductId, productId)
                .orderByDesc(ProductImages::getIsMain)
                .orderByAsc(ProductImages::getSortOrder);

        List<ProductImages> images = productImageMapper.selectList(queryWrapper);

        // 转换为VO
        List<ProductImageVO> voList = images.stream()
                .map(image -> ProductImageVO.builder()
                        .id(image.getId())
                        .productId(image.getProductId())
                        .imageUrl(image.getImageUrl())
                        .isMain(image.getIsMain() == 1)
                        .sortOrder(image.getSortOrder())
                        .build())
                .collect(Collectors.toList());

        // 写入缓存，确保使用普通ArrayList
        redisTemplate.opsForValue().set(cacheKey, new ArrayList<>(voList), CACHE_EXPIRATION, TimeUnit.HOURS);

        return Result.success(voList, "获取成功");
    }

    /**
     * 获取热门商品列表（浏览次数超过100的商品）
     */
    @Override
    public Result<Page<ProductListVO>> getPopularProducts(Pageable pageable) {
        // 尝试从缓存获取
        String cacheKey = CACHE_PRODUCT_POPULAR + ":" + pageable.getPageNumber() + ":" + pageable.getPageSize();
        Object cachedPopular = redisTemplate.opsForValue().get(cacheKey);
        if (cachedPopular != null) {
            try {
                // 将缓存的Map数据转换回Page对象
                Map<String, Object> pageData = (Map<String, Object>) cachedPopular;
                List<ProductListVO> content = (List<ProductListVO>) pageData.get("content");
                long totalElements = ((Number) pageData.get("totalElements")).longValue();
                int number = ((Number) pageData.get("number")).intValue();
                int size = ((Number) pageData.get("size")).intValue();

                Page<ProductListVO> pageResult = new PageImpl<>(
                        content, org.springframework.data.domain.PageRequest.of(number, size), totalElements);

                return Result.success(pageResult, "获取成功(缓存)");
            } catch (Exception e) {
                log.warn("热门商品缓存数据反序列化失败", e);
                // 继续查询数据库
            }
        }

        // 构建查询条件：浏览次数超过100且在售
        LambdaQueryWrapper<Product> queryWrapper = Wrappers.lambdaQuery(Product.class)
                .eq(Product::getStatus, 1) // 只查询在售商品
                .ge(Product::getViews, 100) // 浏览次数超过100的商品
                .orderByDesc(Product::getViews); // 按浏览量降序排序

        // 设置分页
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> mybatisPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                pageable.getPageNumber() + 1, // MyBatis-Plus分页从1开始
                pageable.getPageSize());

        // 打印分页参数用于调试
        log.info("热门商品请求分页参数 - 页码: {}, 每页大小: {}", pageable.getPageNumber(), pageable.getPageSize());

        // 执行查询
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> productPage = page(mybatisPage,
                queryWrapper);

        // 打印查询结果信息用于调试
        log.info("热门商品查询结果 - 总记录数: {}, 总页数: {}, 当前页码: {}, 当前页记录数: {}",
                productPage.getTotal(), productPage.getPages(),
                productPage.getCurrent(), productPage.getRecords().size());

        // 转换为VO
        List<ProductListVO> voList = productPage.getRecords().stream()
                .map(product -> convertToListVO(product, null)) // 传入 null userId
                .collect(Collectors.toList());

        // 创建Spring Data的Page对象，确保使用可序列化的普通ArrayList
        List<ProductListVO> serializableList = new ArrayList<>(voList);
        Page<ProductListVO> resultPage = new PageImpl<>(
                serializableList, pageable, productPage.getTotal());

        // 用于缓存的可序列化Map对象
        Map<String, Object> cacheMap = new HashMap<>();
        cacheMap.put("content", serializableList);
        cacheMap.put("totalElements", productPage.getTotal());
        cacheMap.put("number", pageable.getPageNumber());
        cacheMap.put("size", pageable.getPageSize());

        // 写入缓存，热门商品缓存时间较短，设为2小时
        redisTemplate.opsForValue().set(cacheKey, cacheMap, 2, TimeUnit.HOURS);

        return Result.success(resultPage, "获取成功");
    }

    /**
     * 获取附近商品列表
     */
    @Override
    public Result<List<ProductListVO>> getProductsNearby(Double longitude, Double latitude, Integer radius,
            Integer limit) {
        if (longitude == null || latitude == null) {
            return Result.error(400, "经度和纬度不能为空");
        }

        // 设置默认值
        int searchRadius = radius != null ? radius : 5000; // 默认5000米
        int resultLimit = limit != null ? limit : 20; // 默认20条

        // 构建缓存Key
        // 对位置数据做了网格化处理，将经纬度精确到小数点后两位，以增加缓存命中率
        // 这意味着大约1.1km范围内的查询会共享缓存
        String cacheKey = String.format("%s%.2f:%.2f:%d:%d",
                CACHE_PRODUCT_NEARBY,
                Math.floor(longitude * 100) / 100,
                Math.floor(latitude * 100) / 100,
                searchRadius,
                resultLimit);

        // 尝试从缓存获取
        // 对于附近商品，缓存时间较短
        Object cachedNearby = redisTemplate.opsForValue().get(cacheKey);
        if (cachedNearby != null) {
            try {
                List<ProductListVO> nearbyList = (List<ProductListVO>) cachedNearby;
                return Result.success(new ArrayList<>(nearbyList), "获取成功(缓存)");
            } catch (Exception e) {
                log.warn("附近商品缓存数据反序列化失败", e);
                // 继续查询数据库
            }
        }

        // 查询在售的所有商品
        LambdaQueryWrapper<Product> queryWrapper = Wrappers.lambdaQuery(Product.class)
                .eq(Product::getStatus, 1) // 只查询在售商品
                .isNotNull(Product::getLatitude) // 确保有位置信息
                .isNotNull(Product::getLongitude);

        List<Product> allProducts = list(queryWrapper);

        // 计算距离并过滤
        List<ProductListVO> nearbyProducts = allProducts.stream()
                .filter(product -> product.getLatitude() != null && product.getLongitude() != null)
                .map(product -> {
                    ProductListVO vo = convertToListVO(product, null);
                    // 计算距离
                    double distance = calculateDistanceInMeters(
                            latitude, longitude,
                            product.getLatitude().doubleValue(), product.getLongitude().doubleValue());
                    vo.setDistance(distance);
                    return vo;
                })
                .filter(vo -> vo.getDistance() <= searchRadius) // 只返回指定半径内的商品
                .sorted((a, b) -> Double.compare(a.getDistance(), b.getDistance())) // 按距离升序排序
                .limit(resultLimit) // 限制返回数量
                .collect(Collectors.toList());

        // 写入缓存，位置数据缓存时间较短，确保使用普通ArrayList
        redisTemplate.opsForValue().set(cacheKey, new ArrayList<>(nearbyProducts), 30, TimeUnit.MINUTES);

        return Result.success(nearbyProducts, "获取成功");
    }

    /**
     * 联系卖家
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> contactSeller(Long productId, Long userId, String message) {
        // 获取商品信息
        Product product = this.getById(productId);
        if (product == null) {
            return Result.error(404, "商品不存在");
        }

        // 获取卖家和买家信息
        User seller = userService.getUserById(product.getSellerId());
        User buyer = userService.getUserById(userId);
        if (seller == null) {
            return Result.error(404, "卖家信息获取失败");
        }
        if (buyer == null) {
            return Result.error(404, "用户信息获取失败");
        }

        // 不能联系自己
        if (userId.equals(product.getSellerId())) {
            return Result.error(409, "不能联系自己发布的商品"); // 使用 409 Conflict 更合适
        }

        try {
            // 1. 创建或获取会话
            Long sellerId = product.getSellerId();
            Result<ConversationVO> conversationResult = messageService.createConversation(userId, sellerId);
            if (conversationResult.getCode() != 200) {
                return Result.error(conversationResult.getCode(), "创建或获取会话失败：" + conversationResult.getMessage());
            }

            // 2. 发送用户文本消息
            MessageSendDTO userMessageDTO = new MessageSendDTO();
            userMessageDTO.setReceiverId(sellerId);
            userMessageDTO.setContent(message);
            userMessageDTO.setUserId(userId);

            Result<?> userMessageResult = messageService.sendMessage(userId, userMessageDTO);
            if (userMessageResult.getCode() != 200) {
                // 注意：即使消息发送失败，会话也已创建/获取，但这里为了保持一致性，返回错误
                return Result.error(userMessageResult.getCode(), "发送消息失败：" + userMessageResult.getMessage());
            }

            // 3. 发送商品引用消息 (可选，如果前端需要根据此消息类型渲染商品卡片)
            // 如果 sendMessage 内部能根据 productId 处理商品引用，则此步骤可能不需要显式发送第二条消息
            // 为保持与 contactPublisher 一致，这里发送第二条
            MessageSendDTO productReferenceDTO = new MessageSendDTO();
            productReferenceDTO.setReceiverId(sellerId);
            productReferenceDTO.setUserId(userId);
            productReferenceDTO.setProductId(productId); // 只设置 productId

            Result<?> referenceResult = messageService.sendMessage(userId, productReferenceDTO);
            if (referenceResult.getCode() != 200) {
                // 记录日志或处理错误，但不一定需要阻止成功返回，因为主要消息已发送
                log.warn("发送商品引用消息失败 (productId: {}, buyerId: {}, sellerId: {}): {}",
                        productId, userId, sellerId, referenceResult.getMessage());
                // 可以选择返回成功，因为用户消息已发送
                // return Result.error(referenceResult.getCode(), "发送商品引用失败：" +
                // referenceResult.getMessage());
            }

            // 4. 记录日志
            log.info("用户 {} 联系商品 {} 的卖家 {}, 消息: {}", userId, productId, sellerId, message);

            // 返回会话信息
            return Result.success(conversationResult.getData(), "联系卖家成功"); // 返回 ConversationVO

        } catch (Exception e) {
            log.error("联系卖家时发生异常 (productId: {}, buyerId: {})", productId, userId, e);
            return Result.error(500, "联系卖家时发生内部错误: " + e.getMessage());
        }
    }

    /**
     * 清除商品相关缓存
     * 当商品数据发生变更时调用此方法
     */
    public void clearProductCache(Long productId) {
        if (productId == null) {
            return;
        }
        log.info("清除商品缓存: {}", productId);

        // 删除商品详情缓存
        String detailCacheKey = CACHE_PRODUCT_DETAIL + productId;
        redisTemplate.delete(detailCacheKey);

        // 删除商品图片缓存
        String imagesCacheKey = CACHE_PRODUCT_IMAGES + productId;
        redisTemplate.delete(imagesCacheKey);

        // 清除热门商品缓存 (简单方式是根据key模式匹配删除)
        redisTemplate.delete(CACHE_PRODUCT_POPULAR + "*");

        // 清除可能包含该商品的商品列表缓存
        redisTemplate.delete(CACHE_PRODUCT_LIST + "*");
        redisTemplate.delete(CACHE_PRODUCT_NEARBY + "*");
        redisTemplate.delete(CACHE_PRODUCT_RECOMMENDED + "*");
    }

    /**
     * 获取推荐商品列表
     */
    @Override
    public Result<Page<ProductListVO>> getRecommendedProducts(Long categoryId, Long userId, Integer limit,
            Pageable pageable) {
        try {
            // 构建缓存Key
            StringBuilder cacheKeyBuilder = new StringBuilder(CACHE_PRODUCT_RECOMMENDED);
            cacheKeyBuilder.append("cat:").append(categoryId == null ? "0" : categoryId);
            cacheKeyBuilder.append(":page:").append(pageable.getPageNumber());
            cacheKeyBuilder.append(":size:").append(pageable.getPageSize());
            cacheKeyBuilder.append(":limit:").append(limit == null ? "0" : limit);

            // 用户特定的结果（是否收藏）需要单独的缓存Key
            String cacheKey = cacheKeyBuilder.toString();
            if (userId != null) {
                cacheKey += ":user:" + userId;
            }

            // 尝试从缓存获取
            Object cachedRecommended = redisTemplate.opsForValue().get(cacheKey);
            if (cachedRecommended != null) {
                try {
                    // 将缓存的Map数据转换回Page对象
                    Map<String, Object> pageData = (Map<String, Object>) cachedRecommended;
                    List<ProductListVO> content = (List<ProductListVO>) pageData.get("content");
                    long totalElements = ((Number) pageData.get("totalElements")).longValue();
                    int number = ((Number) pageData.get("number")).intValue();
                    int size = ((Number) pageData.get("size")).intValue();

                    Page<ProductListVO> pageResult = new PageImpl<>(
                            content, org.springframework.data.domain.PageRequest.of(number, size), totalElements);

                    return Result.success(pageResult, "获取成功(缓存)");
                } catch (Exception e) {
                    log.warn("推荐商品缓存数据反序列化失败", e);
                    // 继续查询数据库
                }
            }

            // 创建查询条件
            LambdaQueryWrapper<Product> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(Product::getStatus, 1); // 在售状态为1

            // 如果指定了分类ID，则优先推荐同类别商品
            if (categoryId != null && categoryId > 0) {
                wrapper.eq(Product::getCategoryId, categoryId);
            }

            // 按照浏览量和创建时间排序
            wrapper.orderByDesc(Product::getViews);
            wrapper.orderByDesc(Product::getCreatedAt);

            // 设置分页参数
            int pageNum = pageable.getPageNumber();
            int pageSize = (limit != null && limit > 0) ? Math.min(pageable.getPageSize(), limit)
                    : pageable.getPageSize();

            // 执行分页查询
            com.baomidou.mybatisplus.extension.plugins.pagination.Page<Product> productPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
                    pageNum + 1, pageSize);
            productPage = baseMapper.selectPage(productPage, wrapper);

            // 转换商品列表为VO
            List<ProductListVO> productVOList = new ArrayList<>();
            for (Product product : productPage.getRecords()) {
                ProductListVO vo = new ProductListVO();
                BeanUtils.copyProperties(product, vo);

                // 设置分类名称
                String categoryName = categoryService.getCategoryName(product.getCategoryId());
                if (categoryName != null) {
                    vo.setCategoryName(categoryName);
                }

                // 设置卖家信息
                User seller = userService.getUserById(product.getSellerId());
                if (seller != null) {
                    vo.setSellerName(seller.getUsername());
                    vo.setSellerAvatar(seller.getAvatar());
                }

                // 获取商品主图
                List<ProductImages> imagesList = productImageMapper.selectList(
                        Wrappers.lambdaQuery(ProductImages.class)
                                .eq(ProductImages::getProductId, product.getId())
                                .orderByAsc(ProductImages::getSortOrder)
                                .last("LIMIT 1"));

                if (!imagesList.isEmpty()) {
                    vo.setMainImageUrl(imagesList.get(0).getImageUrl());
                }

                // 设置收藏数和是否收藏
                if (userId != null) {
                    Boolean isFavorite = favoriteService.isFavorite(userId, product.getId());
                    vo.setIsFavorite(isFavorite);
                }

                // 设置收藏数量
                Integer favoriteCount = favoriteService.countProductFavorites(product.getId());
                vo.setFavoriteCount(favoriteCount);

                vo.setCreateTime(product.getCreatedAt());

                productVOList.add(vo);
            }

            // 确保使用可序列化的ArrayList
            List<ProductListVO> serializableList = new ArrayList<>(productVOList);

            // 创建Spring Data分页结果
            Page<ProductListVO> resultPage = new PageImpl<>(
                    serializableList,
                    pageable,
                    productPage.getTotal());

            // 用于缓存的可序列化Map对象
            Map<String, Object> cacheMap = new HashMap<>();
            cacheMap.put("content", serializableList);
            cacheMap.put("totalElements", productPage.getTotal());
            cacheMap.put("number", pageable.getPageNumber());
            cacheMap.put("size", pageable.getPageSize());

            // 写入缓存，推荐结果缓存时间较长
            redisTemplate.opsForValue().set(cacheKey, cacheMap, CACHE_EXPIRATION, TimeUnit.HOURS);

            return Result.success(resultPage);
        } catch (Exception e) {
            log.error("获取推荐商品列表失败", e);
            return Result.error("获取推荐商品列表失败");
        }
    }
}